
class OutputDataStream
{
public:
    OutputDataStream();
    ~OutputDataStream();
    void FreeMemory();

    //
    // Saves stream to a file
    //
    void SaveToFile(const string &filename);
    void SaveToFileNoHeader(const string &Filename);
    //void SaveToCompressedFile(const string &filename);
    
    //
    // Writes data represented by T as binary data to the stream
    //
    template<class type> inline void WriteData(const type &T)
    {
        const UINT ByteCount = sizeof(T);
        const UINT StartLength = _data.size();
        _data.resize(StartLength + ByteCount);
        BYTE *StreamOffset = &(_data[0]) + StartLength;
        const BYTE *TOffset = (const BYTE *)&T;
        for(UINT ByteIndex = 0; ByteIndex < ByteCount; ByteIndex++)
        {
            *StreamOffset = *TOffset;
            StreamOffset++;
            TOffset++;
        }
    }

    //
    // Writes raw binary data to the stream
    //
    void WriteData(const BYTE *Data, UINT BytesToWrite);
    
    template<class type> void WriteSimpleVector(const vector<type> &v)
    {
        const UINT length = v.size();
        *this << length;
        if(length > 0)
        {
            WriteData((BYTE *)(&v[0]), length * sizeof(type));
        }
    }

    inline const vector<BYTE>& Data() const
    {
        return _data;
    }

protected:
    vector<BYTE> _data;
};

//
// Output for several basic types
//
template<class A, class B>
inline OutputDataStream& operator << (OutputDataStream &S, const pair<A,B> &P)
{
    S << P.first;
    S << P.second;
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, BYTE A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, UINT A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, int A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, float A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, double A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, char A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, bool A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, RGBColor A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, unsigned short A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, UINT64 A)
{
    S.WriteData(A);
    return S;
}

inline OutputDataStream& operator << (OutputDataStream &S, const Vec2i &A)
{
    S.WriteData(A);
    return S;
}

template<class type> OutputDataStream& operator << (OutputDataStream &S, const vector<type> &V)
{
    UINT length = V.size();
    S << length;
    for(UINT index = 0; index < length; index++)
    {
        S << V[index];
    }
    return S;
}

OutputDataStream& operator << (OutputDataStream &S, const string &V);